package com.huangxunyi.GUET;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.Calendar;
import java.util.Collections;
import java.util.ListIterator;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

/**
 * //=======================================================
 * //		          .----.
 * //		       _.'__    `.
 * //		   .--(^)(^^)---/!\
 * //		 .' @          /!!!\
 * //		 :         ,    !!!!
 * //		  `-..__.-' _.-\!!!/
 * //		        `;_:    `"'
 * //		      .'"""""`.
 * //		     /,  ya ,\\
 * //		    //狗神保佑\\
 * //		    `-._______.-'
 * //		    ___`. | .'___
 * //		   (______|______)
 * //=======================================================
 * Created by huang on 2017/2/25.
 */
public class UIIpclient implements ActionListener {
    private final String WAIT_RE_CONNENTING = "等待重连中..";
    private final static int TIME_TIMEOUT_FOR_RE_LOGIN = 1 * 1000;
    private final static String accsFileName = IPClientUtils.getProjectPath()
            + "account.dat";
    private final static String WRONG_USERNAME_OR_PASSWORD = "用户名或密码错误";
    private final static String NOT_ENOUGH_MONEY = "您的钱不够了";
    private final static String NOT_RESPONSE = "服务器无响应";
    private final static String OPENNING = "开放中...";
    private final static String CONNENTING = "正在连接..";
    private Vector<Vector<String>> accList = new Vector<Vector<String>>();
    private ListIterator<Vector<String>> curIt = accList.listIterator();

    private int curMonth = Calendar.getInstance().get(Calendar.MONDAY) + 1;
    private Vector<String> preAccItem = null;

    private IpClient mIpClient;

    private int popupSelectRow = 0;

    private JFrame jFrame = new JFrame("ipclient");

    private JTable accsTable;

    private JButton startBn = new JButton("Start");
    private JButton stopBn = new JButton("Stop");
    private JButton refreshBn = new JButton("Refresh");
    private JButton addAccountBn = new JButton("Add Account");
    private JButton savebn = new JButton("Save");
    private JPopupMenu accsMenu;
    private JMenuItem openItem = new JMenuItem("Login");
    private JMenuItem deleteItem = new JMenuItem("Delete");

    private JLabel flowLbl = new JLabel("流量：");
    private JLabel moneyLbl = new JLabel("余额：");
    private JLabel msgLbl = new JLabel("Stop");
    private JLabel ipLbl = new JLabel();

    private DefaultTableModel accsTableModel;
    private String[] accsTitles = {"帐号", "密码", "余额", "备注"};
    private Vector<String> title = new Vector<String>();

    private RefreshThread refreshThread;
    private boolean haveIp = false;
    private int perAccsHashCode;

    public UIIpclient() {
        mIpClient = IpClient.getInstance();
        creatUI();
        new Thread() {
            @Override
            public void run() {
                if (!updateIp())
                    msgLbl.setText(NOT_RESPONSE);
            }
        }.start();

    }

    public void creatUI() {

        initJFrame1();
        initTopPanel();
        initAccsTable();
        initBottomPanel();
        initJFrame2();
        trayDemo();
        listenExit();
    }

    /**
     * 监听程序退出，退出着保存数据
     */
    private void listenExit() {
        jFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {

                if (perAccsHashCode != accList.hashCode()) {
                    int result = JOptionPane.showConfirmDialog(jFrame, "是否保存数据", "提示", JOptionPane.YES_NO_OPTION);
                    jFrame.setVisible(false);
                    switch (result) {
                        case JOptionPane.OK_OPTION:
                            new Thread() {
                                @Override
                                public void run() {
                                    try {
                                        IPClientUtils.writeAccounts(accsFileName, accList);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                    System.exit(0);
                                }
                            }.start();

                            break;
                        case JOptionPane.NO_OPTION:
                            System.exit(0);
                            break;
                        default:
                            break;
                    }
                } else {
                    jFrame.setVisible(false);
                    System.exit(0);
                }

            }
        });
    }

    private void initJFrame1() {

        String lookAndFeel = UIManager.getSystemLookAndFeelClassName();
        try {
            UIManager.setLookAndFeel(lookAndFeel);
        } catch (Exception e) {
            e.printStackTrace();
        }
        jFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        jFrame.setResizable(false);
        jFrame.setLayout(new BorderLayout(0, 5));
    }

    private void initJFrame2() {
        jFrame.pack();
        jFrame.setLocationRelativeTo(null);
        jFrame.setVisible(true);
    }

    private void initTopPanel() {

        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 10));
        topPanel.add(startBn);
        startBn.addActionListener(this);
        topPanel.add(stopBn);
        stopBn.addActionListener(this);
        topPanel.add(refreshBn);
        refreshBn.addActionListener(this);
        topPanel.add(addAccountBn);
        addAccountBn.addActionListener(this);
        topPanel.add(savebn);
        savebn.addActionListener(this);
        jFrame.add(topPanel, BorderLayout.NORTH);

    }

    private void initAccsTable() {

        // 设置表格标题
        title.clear();
        Collections.addAll(title, accsTitles);
        // 声明表格的数据model
        accsTableModel = new DefaultTableModel() {
            @Override
            public boolean isCellEditable(int row, int column) {
                return column != 2 && column != 3;
            }
        };
        accsTableModel.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                if (e.getType() == TableModelEvent.UPDATE) {
                    if (e.getColumn() == 0 || e.getColumn() == 1) {
                        accsTableModel.setValueAt("", e.getFirstRow(), 3);
                    }
                }
            }
        });
        accsTable = new JTable(accsTableModel);
        // 多线程加载数据
        loadAccs();
        // 定义右键帐号列表事件
        accsMenu = new JPopupMenu();
        openItem.addActionListener(this);
        deleteItem.addActionListener(this);
        accsMenu.add(openItem);
        accsMenu.add(deleteItem);
        accsTable.addMouseListener(new MouseAdapter() {
            private void handleMouseEvent(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    popupSelectRow = e.getY() / accsTable.getRowHeight();
                    accsMenu.show(e.getComponent(), e.getX(), e.getY());
                    accsTable.setRowSelectionInterval(popupSelectRow,
                            popupSelectRow);
                }
            }

            /**
             *handle mouse event for the Solaris
             */
            @Override
            public void mousePressed(MouseEvent e) {
                handleMouseEvent(e);
            }

            /**
             *handle mouse event for the windows
             */
            @Override
            public void mouseReleased(MouseEvent e) {
                handleMouseEvent(e);
            }
        });
        // 将表格添加到界面中
        jFrame.add(new JScrollPane(accsTable));
    }

    private void initBottomPanel() {

        JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 20));
        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
        Panel flowPanel = new Panel(new FlowLayout(FlowLayout.LEFT, 20, 5));
        Panel moneyPanel = new Panel(new FlowLayout(FlowLayout.LEFT, 20, 5));
        Panel msgPanel = new Panel(new FlowLayout(FlowLayout.LEFT, 20, 5));
        Panel ipPanel = new Panel(new FlowLayout(FlowLayout.RIGHT, 20, 5));
        flowLbl.setMinimumSize(new Dimension(200, 0));
        moneyLbl.setMinimumSize(new Dimension(200, 0));
        msgLbl.setMinimumSize(new Dimension(200, 0));
        ipLbl.setMinimumSize(new Dimension(200, 0));
        flowPanel.add(flowLbl);
        moneyPanel.add(moneyLbl);
        msgPanel.add(msgLbl);
        ipPanel.add(ipLbl);
        bottomPanel.add(flowPanel);
        bottomPanel.add(moneyPanel);
        bottomPanel.add(msgPanel);
        bottomPanel.add(ipPanel);
        jFrame.add(bottomPanel, BorderLayout.SOUTH);
    }


    public void trayDemo() {

        SystemTray systemTray = SystemTray.getSystemTray();
        try {
            TrayIcon trayIcon = new TrayIcon(ImageIO.read(new ByteArrayInputStream(IconFile.data)));
            systemTray.add(trayIcon);
            trayIcon.setImageAutoSize(true);

            jFrame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowIconified(WindowEvent event) {
                    jFrame.dispose();
                }
            });
            trayIcon.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {

                    jFrame.setAlwaysOnTop(true);
                    if (e.getClickCount() == MouseEvent.BUTTON1) {
                        int state = jFrame.getExtendedState();
                        if (state == JFrame.ICONIFIED) {
                            jFrame.setExtendedState(JFrame.NORMAL);
                            jFrame.setVisible(true);
                        } else if (state == JFrame.NORMAL || state == JFrame.MAXIMIZED_BOTH) {
                            jFrame.setExtendedState(JFrame.ICONIFIED);
                        }
                    }
                    jFrame.setAlwaysOnTop(false);

                }
            });
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (AWTException e1) {
            e1.printStackTrace();
        }
    }

    private boolean isRefresh = true;

    public void stopRefresh() {
        isRefresh = false;
    }

    private class RefreshThread extends Thread {

        @Override
        public void run() {
            isRefresh = true;
            mIpClient = IpClient.getInstance();
            while (isRefresh) {
                if (mIpClient.isLogin()) { //已登录
                    try {
                        mIpClient.refreshOnline();
                        refreshFlowAndMoney();
                    } catch (RefreshFaileException e) {    //刷新失败
                        if (e.getInfo().equals(IpClient.NOT_ENOUGH_MONEY)) {
                            setCurItemInfo(NOT_ENOUGH_MONEY);
                            accList.get(curIt.nextIndex() - 1).set(2,
                                    String.format("%d月/%.2f元", curMonth, 0.0));
                            accsTableModel.fireTableDataChanged();
                            if (loginNext()) {
                                continue;
                            }
                        } else if (e.getInfo().equals(IpClient.SERVER_NO_RESPONSE)) {
                            clearPreItemInfo();
                            //判断网络是否正常
                            if (updateIp()) {
                                if (curIt.hasPrevious())
                                    curIt.previous();
                                if (loginNext()) {
                                    continue;
                                }
                            } else {
                                mIpClient.setLogin(false);
                                setCurItemInfo(NOT_RESPONSE);
                                msgLbl.setText(WAIT_RE_CONNENTING);
                                if (curIt.hasPrevious())
                                    curIt.previous();
                            }
                        }
                    }

                } else { //未登录
                    if (loginNext()) {
                        if (!haveIp) {
                            updateIp();
                        }
                        continue;
                    }

                }

                try {
                    Thread.sleep(IpClient.TIME_REFRESH_ONLINE_INTERVAL);
                } catch (InterruptedException ignored) {
                }

            }
        }
    }

    /**
     * 找到下一个可用账号并尝试登录
     */
    private synchronized boolean loginNext() {

        Vector<String> curAccAry;
        while (curIt.hasNext()) {
            if (!isRefresh) {
                return false;
            }
            curAccAry = curIt.next();
            double money = 10;
            try {
                String m = curAccAry.get(2).split("/")[1];
                m = m.split("元")[0];
                money = Double.parseDouble(m);
            } catch (Exception ignored) {
            }
            if (curAccAry.get(3).equals(WRONG_USERNAME_OR_PASSWORD)
                    || money < 0.01) {
                continue;
            }
            mIpClient.setUserInfo(curAccAry.get(0), curAccAry.get(1));
            try {
                msgLbl.setText(CONNENTING);
                msgLbl.setText(mIpClient.login());
                clearPreItemInfo();
                setCurItemInfo(OPENNING);
                preAccItem = accList.get(curIt.nextIndex() - 1);
                return true;

            } catch (LoginFaileException e) {
                clearPreItemInfo();
                if (e.getInfo().equals(NOT_RESPONSE)) {
                    msgLbl.setText(WAIT_RE_CONNENTING);
                    setCurItemInfo(NOT_RESPONSE);
                    if (curIt.hasPrevious())
                        curIt.previous();
                    return false;
                } else {
                    callBack(e.getInfo());
                }

            }
        }
        handleStop();
        msgLbl.setText("帐号已用完！");
        clearPreItemInfo();
        curIt = accList.listIterator();
        return false;
    }

    private void setCurItemInfo(String info) {
        accsTableModel.setValueAt(info, curIt.nextIndex() - 1, 3);
        accsTableModel.fireTableDataChanged();
    }

    private void clearPreItemInfo() {
        if (preAccItem != null) {
            preAccItem.set(3, "");
            accsTableModel.fireTableDataChanged();
        }
    }

    /**
     * handle WRONG_USERNAME_OR_PASSWORD and NOT_ENOUGH_MONEY
     */
    public void callBack(String msg) {
        System.err.println(mIpClient.getUsername() + "  " + mIpClient.getPassword() + "\n" + msg);
        mIpClient.setLogin(false);
        flowLbl.setText("流量：");
        moneyLbl.setText("余额：");
        msgLbl.setText(msg);
        setCurItemInfo(msg);
        if (msg.equals(NOT_ENOUGH_MONEY)) {
            accList.get(curIt.nextIndex() - 1).set(2,
                    String.format("%d月/%.2f元", curMonth, 0.0));
            accsTableModel.fireTableDataChanged();
        }
        try {
            Thread.sleep(TIME_TIMEOUT_FOR_RE_LOGIN);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void begin() {

        if (refreshThread == null) {
            refreshThread = new RefreshThread();
            refreshThread.start();
        } else {
            mIpClient.setLogin(false);
            refreshThread.interrupt();
        }

    }

    private void handleRefresh() {
//        new Thread() {
//            @Override
//            public void run() {
//                try {
//                    mIpClient.refreshOnline();
//                    refreshFlowAndMoney();
//                } catch (RefreshFaileException e) {
//                    msgLbl.setText(e.getInfo());
//                }
//            }
//        }.start();
        if (mIpClient.isLogin()) {
            if (refreshThread.getState().equals(Thread.State.TIMED_WAITING)) {
                refreshThread.interrupt();
            }
        } else {
            msgLbl.setText("您还没有登录");
        }
    }


    private void handleStop() {
        if (refreshThread != null) {
            stopRefresh();
            refreshThread.interrupt();
            refreshThread.interrupt();
            refreshThread.interrupt();
            refreshThread = null;
        }
        flowLbl.setText("流量：");
        moneyLbl.setText("余额：");
        msgLbl.setText("Stop");
        new Thread() {
            @Override
            public void run() {
                try {

                    if (mIpClient.isLogin()) {
                        mIpClient.logout();
                        clearPreItemInfo();
                        accsTableModel.setValueAt("", curIt.nextIndex() - 1, 3);
                        curIt = accList.listIterator();
                    }
                } catch (LogoutFaileException ignored) {
                }
            }
        }.start();

    }

    /**
     * 多线程载入账号
     */
    private void loadAccs() {
        new Thread() {
            @Override
            public void run() {
                try {
                    accList = IPClientUtils.loadAccounts(accsFileName);
                    perAccsHashCode = accList.hashCode();
                    accsTableModel.setDataVector(accList, title);
                    curIt = accList.listIterator();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * 多线程保存数据
     */
    private void saveAccs() {
        new Thread() {
            @Override
            public void run() {
                try {
                    IPClientUtils.writeAccounts(accsFileName, accList);
                    perAccsHashCode = accList.hashCode();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * 更新ip，通过获取ip判断网络是否可用
     *
     * @return 网络是否可用
     */
    private boolean updateIp() {
        try {
            msgLbl.setText(CONNENTING);
            ipLbl.setText(mIpClient.getIP());
            msgLbl.setText("");
            haveIp = true;
            return true;
        } catch (RefreshFaileException e) {
            ipLbl.setText("无法获取到IP");
            haveIp = false;
            return false;
        }

    }

    /**
     * 刷新流量和余额
     */
    private void refreshFlowAndMoney() {
        try {

            if (mIpClient.getFlow() / 1024 / 1024 >= 1) {
                flowLbl.setText(String.format("流量：%.3fMb",
                        mIpClient.getFlow() / 1024 / 1024));
            } else {
                flowLbl.setText(String.format("流量：%.3fKb",
                        mIpClient.getFlow() / 1024));
            }
            moneyLbl.setText(String.format("余额：%.2f元", mIpClient.getMoney()));
            accList.get(curIt.nextIndex() - 1).set(2,
                    String.format("%d月/%.2f元", curMonth, mIpClient.getMoney()));
            accsTableModel.fireTableDataChanged();

            System.out.println("流量：" + mIpClient.getFlow() + "b   余额："
                    + mIpClient.getMoney() + "元");
        } catch (Exception ignored) {
        }
    }

    private void removeItem() {
        int curIndex = curIt.nextIndex();
        if (popupSelectRow == curIndex) {
            JOptionPane.showMessageDialog(null, "当前账号正在开放中");
            return;
        }
        accList.remove(popupSelectRow);
        accsTableModel.fireTableDataChanged();
        if (popupSelectRow < curIndex) {
            curIndex--;
        }
        curIt = accList.listIterator(curIndex);
    }

    private void addItem() {
        int curIndex = curIt.nextIndex();
        Vector<String> data = new Vector<String>();
        Collections.addAll(data, "*帐号*", "*密码*", "", "");
        accList.add(data);
        accsTableModel.fireTableDataChanged();
        curIt = accList.listIterator(curIndex);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource().equals(openItem)) {
            curIt = accList.listIterator(popupSelectRow);
            begin();
        } else if (e.getSource().equals(deleteItem)) {
            removeItem();
        } else if (e.getSource().equals(startBn)) {
            begin();
        } else if (e.getSource().equals(stopBn)) {
            handleStop();
        } else if (e.getSource().equals(refreshBn)) {
            handleRefresh();
        } else if (e.getSource().equals(addAccountBn)) {
            addItem();
        } else if (e.getSource() == savebn) {
            saveAccs();
            JOptionPane.showMessageDialog(jFrame, "保存成功！");
        }
    }
}
